# coding=utf-8

import json
import sys

import requests
from urllib.parse import urljoin
import time
import os
import traceback
from requests.exceptions import HTTPError, ConnectionError, Timeout, RequestException
# relAppId = "7576151"
# relAppId=os.environ.get("relAppId", '7576151')
#
# # appId = "7576152"
# appId=os.environ.get("appId", '7576152')
#
# # appSecret = "eb820f3ee12219022892366b729902e7"
# appSecret=os.environ.get("appSecret", 'eb820f3ee12219022892366b729902e7')


# SRV_HOST="192.168.176.61"
# SRV_HOST="192.168.176.63"


#服务器 内网
# DAWATE_PORT=os.environ.get("DAWATE_PORT", '5030')
# DAWATE_HOST=os.environ.get("DAWATE_HOST", '10.10.65.104')
# base_url = f'https://{DAWATE_HOST}:{DAWATE_PORT}'

#wifi
# DAWATE_PORT = os.environ.get("DAWATE_PORT", '5030')
# DAWATE_HOST = os.environ.get("DAWATE_HOST", '192.168.43.12')
# base_url = f'http://{DAWATE_HOST}:{DAWATE_PORT}'



#本地
DAWATE_PORT = os.environ.get("DAWATE_PORT", '5030')
DAWATE_HOST = os.environ.get("DAWATE_HOST", '10.111.61.235')
base_url = f'http://{DAWATE_HOST}:{DAWATE_PORT}'

# SRV_PORT=7234

# DAWATE_PORT = int(SRV_PORT)

# DAWATE_HOST=10.111.61.235 DAWATE_PORT=15030 python intf-da-wa-te.py

# base_url = 'https://10.10.65.104:5030'

# base_url = 'https://10.111.61.235:25030'


# print(f'\n---------------- env DAWATE_HOST: {DAWATE_HOST}, DAWATE_PORT: {DAWATE_PORT} , base_url: {base_url} ----------------\n')


debug_info = False

def show_json_response(response):
    if debug_info:
        print(f'\n---------------- response url: {response.url}: , return json: ----------------\n{json.loads(response.content)} \n---------------- ----------------\n')

DftuProxies = None

DFT_DAWATE_PROXY = os.environ.get("DFT_DAWATE_PROXY")

if DFT_DAWATE_PROXY is not None:
    DftuProxies = {
        'http': DFT_DAWATE_PROXY,
        'https': DFT_DAWATE_PROXY,
    }
    #(f'\n---------------- env DAWATE_HOST: {DAWATE_HOST}, DAWATE_PORT: {DAWATE_PORT} , base_url: {base_url} , proxies: {DftuProxies} ----------------\n')


DefJsonHeaders = {
        "Content-Type": "application/json",
    #     "appId": appId,
    #     "appKey": appkey
    }
DefJsonoStreamHeaders = {
        "Content-Type": "application/octet-stream",
    #     "appId": appId,
    #     "appKey": appkey
    }

def obj2json_str(objdata):
    return json.dumps(objdata,ensure_ascii=False)

def post_json(url,objdata, specheaders=None, stream=False):

    #请求参数
    #print(f'\n---------------- post_json url: {url} ----------------\n ---------------- headers: ----------------\n{specheaders} \n---------------- json: ----------------\n{objdata}\n----------------\n')
    # print(f'\n---------------- curl: ----------------\ncurl -i -k -X POST "{url}" -H "Content-Type:application/json" -H "appId: {appId}" -H "appKey: {appkey}" -d \'{objdata}\'\n----------------\n')

    # 发送请求并读取响应
    if specheaders is None:
        if stream:
            specheaders = DefJsonoStreamHeaders
        else:
            specheaders = DefJsonHeaders
        
    request_params = obj2json_str(objdata)
    try:
        response = requests.post(url, headers=specheaders, data=request_params.encode('utf-8'), verify=False, stream=stream, proxies=DftuProxies)
        response.encoding = 'utf-8'
    except HTTPError as http_err:
        response =f"HTTP error occurred: {http_err}"  # 返回HTTP错误信息
    except ConnectionError as conn_err:
        response = f"Connection error occurred: {conn_err}"  # 返回连接错误信息
    except Timeout as timeout_err:
        response = f"Timeout error occurred: {timeout_err}"  # 返回超时错误信息
    except RequestException as req_err:
        response = f"Request exception occurred: {req_err}"  # 返回请求异常信息
    except Exception as err:
        response = f"An error occurred: {err}"  # 返回其他错误信息

    return response  # 如果请求成功，返回

    # except:
    #     s=str(traceback.format_exc())
    #     response = str(traceback.format_exc()).split('\n')[-1]
    #     status = False
    # response = requests.post(url, headers=specheaders, json=objdata, verify=False, stream=stream, proxies=DftuProxies)

    # print(response.content)
    


    # return response


def post_json_2_dawate(url,objdata, stream=False):
    #表头
    headers = {
        "Content-Type": "application/json",
        "appId": appId,
        "appKey": appkey
    }

    #请求参数
    # print(f'\n---------------- headers: ----------------\n{headers} \n---------------- json: ----------------\n{objdata}\n----------------\n')
    # print(f'\n---------------- curl cmd: ----------------\ncurl -i -k -X POST "{url}" -H "Content-Type:application/json" -H "appId: {appId}" -H "appKey: {appkey}" -d \'{obj2json_str(objdata)}\'\n----------------\n')

    response=post_json(url, objdata, headers, stream)
    # print("response:",response.text)
    resultMsg=check_error_response(response)

    return response,resultMsg



appkey = None

url_get_apiKey = f"{base_url}/knowledgeService/extSecret/generateAppKey"

def update_appkey(isForce: bool = False):
    global appkey

    # if not isForce and appkey is not None:
    #     # appkey = get_apiKey(appId, appSecret)
        
    #     return
    if not isForce:
        # appkey = get_apiKey(appId, appSecret)
        
        return

    # #请求参数
    request_params = {
        "appId": appId,
        "appSecret":appSecret
    }

    #print(f'\n---------------- curl cmd: ----------------\ncurl -i -k -X POST "{url_get_apiKey}" -H "Content-Type:application/json" -d \'{obj2json_str(request_params)}\'\n----------------\n')

    response = post_json(url_get_apiKey, request_params)
    if "error" in response:
        #print("appkey没有响应")
        return False
    # global appkey
    else:
        #获取响应的appkey
        appkey = json.loads(response.text)['resultObject']['appKey']
        #print(f'\n-------------------------------- update appkey: {appkey} --------------------------------\n')

        return True

url_get_ansewr = f"{base_url}/knowledgeService/extChatApi/chat"

def get_ansewr_response(messages, stream=False):
    update_appkey(True)
    global DftMaxOutTokens,DftPresencePenalty
    maxTokens = DftMaxOutTokens
    presencePenalty = DftPresencePenalty
    #请求参数
    request_params = {
        "relAppId": relAppId,
        "max_tokens":maxTokens,
        "presence_penalty":presencePenalty,
        "messages": messages
    }

    return post_json_2_dawate(url_get_ansewr, request_params, stream)


def get_ansewr(messages):
    response,resultMsg = get_ansewr_response(messages)
    # response,resultMsg = get_ansewr_response(messages,stream=True)
    if "error" in response:
        return  {'content':response}
    else:
        errmsg = check_error_response(response, False)
    if errmsg is not None:
        return {'content':MsgEchoFail}

    # print(response.text)
    # 输出响应
    res = response.text.split('event: answer-qw')[-2].replace('data: ','').split('event: moduleStatus')[0]
    #("resultMsg:",resultMsg,res)
    if res:
        answer = json.loads(res)['choices'][0]["delta"]
    else:
        answer= {'content':""}
    return answer



TokenStreamEnd = "data: [DONE]"

def generate_chunk_delta(content, finish_reason=None, model="", id="1368367384710074368", object=''):
    chunk_delta =  {"model":model,"id":id,"choices":[{"finish_reason":finish_reason,"delta":{"role":"assistant","content":content},"index":0}],"created":0,"object":object}
    return chunk_delta


def generate_error_chunks(messages):
    yield f"data: {obj2json_str('')}\n\n"
    for msg in messages:
        answer = generate_chunk_delta(msg)
        yield f"data: {obj2json_str(answer)}\n\n"
        
    yield f"{TokenStreamEnd}\n\n"


MarksTokenFail = '令牌不存在或过期'

MsgFail = "大瓦特服务调用时发生错误，请重试。"

MsgEchoFail = '服务走丢了，再试一次'

def check_error_response(response, updateAppkey=True):
    resultMsg = None

    if response.status_code != 200:
        #print(f'\n-------------------------------- Error! ---- response.status_code: {response.status_code} --------------------------------\nresponse.content:\n{response.content}\n----------------------------------------------------------------\n')
        
        ret = json.loads(response.content)


        # {"data":null,"isUpdate":null,"model":null,"requestId":null,"resultCode":"-1","resultMsg":"\xe6\x97\xa0\xe6\x9d\x83\xe8\xae\xbf\xe9\x97\xae","resultObject":null}


        if ret.get("resultCode", "") == "-1":
            resultMsg = ret.get("resultMsg")
            #print(f'\n---------------- resultMsg: {resultMsg} ----------------\n')
        
        if resultMsg is None:
            resultMsg = MsgFail

        else:
            if updateAppkey and resultMsg.find(MarksTokenFail) >= 0:
                update_appkey(True)
            
            resultMsg = f'大瓦特服务调用时发生错误，请重试。可能的原因：{resultMsg}'

        ret['resultMsg'] = resultMsg

        resultMsg = ret
    
    return resultMsg

def chat_transfer_stream(messages):
    # global DftMaxOutTokens,DftPresencePenalty
    # max_new_tokens = DftMaxOutTokens
    # presencePenalty = DftPresencePenalty
    # if max_new_tokens is None:
    #     max_new_tokens = DftMaxOutTokens
    #
    # if presencePenalty is None:
    #     presencePenalty = DftPresencePenalty
    
    response, resultMsg = get_ansewr_response(messages, True)

    # print(response,resultMsg)
    
    #如果error，重试一次
    # if response.status_code != 200:
    #     errMsg = check_error_response(response)
    #     # errMsg = check_error_response(response,False)

    #     response, resultMsg = get_ansewr_response(messages, True)

        # return generate_error_chunks([MsgEchoFail])
    
    if response.status_code != 200:
        errMsg = check_error_response(response,False)
        return generate_error_chunks([MsgEchoFail])
 
    def generate_chunks():
        # 对响应结果进行迭代处理每一组数据（一次一行）
        # response = ''
        # tmp = history
        lenAnswer = 0
        for line in response.iter_lines(decode_unicode=True):  # unicode解码方式
            # print(f'line: {line}')
            if line:
                line = line[6:]
                # print(f'line: {line}')
                if line == "[DONE]":
                    # line = json.loads(line)
                    # print(f"data: {line}\n\n")
                    yield TokenStreamEnd
                    # continue

                elif  line == " moduleStatus":
                    # line = json.loads(line)
                    continue
                
                elif  line == " answer-qw":
                    # line = json.loads(line)
                    continue
                
                elif  line.find('"resultMsg":"[令牌不存在或过期]') != -1:
                    # line = json.loads(line)
                    update_appkey(True)
                    continue
                    # break

                
                elif  line.find('"moduleId":"思考中"') != -1:
                    # line = json.loads(line)
                    continue
                
                elif  line.find('"moduleId":"回答中"') != -1:
                    # line = json.loads(line)
                    continue
                
                elif  line.find('"name":"运行结束"') != -1:
                    # line = json.loads(line)
                    continue
                
                elif  line.find(',"delta":{"') != -1:
                    # {"model":"","id":"1368367384710074368","choices":[{"finish_reason":null,"delta":{"role":"assistant","content":"我是阿里云"},"index":0}],"created":0,"object":""}
                    
                    answer = json.loads(line)
                    content = answer['choices'][0]['delta']['content']
                    lenContent = len(content)
                    content = content[lenAnswer:]
                    answer['choices'][0]['delta']['content'] = content
                    lenAnswer = lenContent

                    answer['model'] = 'daWaTe01'
                    
                    ansNew = f"data: {obj2json_str(answer)}\n\n"

                    # print(ansNew)

                    yield ansNew
                    continue
                

                else:
                    # print(f"data: {line}\n\n")
                    # yield f"data: {line}\n\n"
                    # and line != "[DONE]"
                    continue

    # 输出响应
    return generate_chunks()

def chat(messages):
    # messages = []
    # input_text = {"role": "user", "content": text}
    # messages.append(input_text)
    #print(messages)
    st = time.time()
    answer = get_ansewr(messages)
    # print('回答:',answer)
    messages.append(answer)
    ##print("耗时：{}\n大瓦特：\n".format(time.time() - st) , answer)
    return answer['content']


def chat_stream(messages):
    # messages = []
    # input_text = {"role": "user", "content": text}
    # messages.append(input_text)
    #print(messages)
    st = time.time()
    response = chat_transfer_stream(messages)

    # for line in response.iter_lines(decode_unicode=True):  # unicode解码方式
    for line in response:  # unicode解码方式
        # print(f'line: {line}')
        if line:
            # print(line)
            if line.find(TokenStreamEnd) == 0:
                #print(line)
                break
            
            line = line[6:]
            # print([json.loads(line)['choices'][0]['delta']['content']])
            yield json.loads(line)['choices'][0]['delta']['content']
            # print('回答：',line)
            #print(line)
            # print(f'---- data: {line} ----')
            
            # print(f'chunk: {json.loads(line)}')
DftMaxOutTokens = 8000
DftPresencePenalty = 1.05
relAppId = os.environ.get("relAppId", "7576151")
appId = os.environ.get("appId", "7576152")
appSecret = os.environ.get("appSecret", "eb820f3ee12219022892366b729902e7")
# # 单独运行此脚本
# def main(dict):
#     #dict={"DftPresencePenalty":1.05,"DftMaxOutTokens":8000,"question":"你好，你是谁","relAppId":"7576151","appId":"7576152","appSecret":"eb820f3ee12219022892366b729902e7"}
#     # "max_tokens": maxTokens,
#     # "presence_penalty": presencePenalty,
#     global relAppId,appId,appSecret
#     if dict["relAppId"]:
#         relAppId = os.environ.get("relAppId", dict["relAppId"])
#     if dict["appId"]:
#         appId = os.environ.get("appId", dict["appId"])
#     if dict["appSecret"]:
#         appSecret = os.environ.get("appSecret", dict["appSecret"])
#     if update_appkey(True) is True:
#         # responce_content=chat(dict["messages"]) #MsgFail '大瓦特服务调用时发生错误，请重试。'
#
#         if not responce_content:
#             responce_content="模型没有响应,请多试几次"
#     else:
#         responce_content="appkey没有响应"
#     # print("responce_content:",responce_content)
#     return responce_content


#测试
# def a():
#     lines = ['#', '##', ' 数', '字运', '营系', '统项目概', '况', '\n\n', '截至', '目前', '，数', '字运', '营', '系统', '正在', '执', '行', '的', '项', '目', '共', '计4', '6', '2个', '（不', '包括', '待结', '算项', '目）', '，所', '有', '项', '目均', '已', '录入', '禅道', '系统', '。具体', '分', '类如下', '：\n', '\n-', ' ', '**', '产品', '销', '售', '类', '项', '目', '**：', '8个', '\n-', ' ', '**', '工程', '集', '成', '类', '项', '目', '**：', '5个', '\n-', ' ', '**', '开发', '实', '施', '类', '项', '目', '*', '*', '：25', '7个', '\n-', ' ', '**', '研究', '咨', '询', '类', '项', '目', '*', '*：1', '8个', '\n', '- ', '**', '运', '维', '类', '项', '目', '*', '*', '：10', '6个', '\n-', ' ', '**', '资源', '租', '赁', '类', '项', '目*', '*：', '6', '8个', '\n\n', '目', '前', '，各', '项项目均', '按', '计划有序推进。']
#
#
#     for line in lines:
#         time.sleep(0.1)
#         # yield json.loads(line)['choices'][0]['delta']
#         yield line

# 单独运行此脚本
def main_stream(dict):
    # 本地测试
    # 手动迭代生成器
    # responce_content_stream = a()
    # try:
    #     while True:
    #         responce_content = next(responce_content_stream)  # 获取下一个yield产生的值
    #         yield responce_content
    # except StopIteration:
    #     # 生成器没有更多的值可以产生时，会抛出StopIteration异常
    #     pass

    global relAppId, appId, appSecret
    if dict["relAppId"]:
        relAppId = os.environ.get("relAppId", dict["relAppId"])
    if dict["appId"]:
        appId = os.environ.get("appId", dict["appId"])
    if dict["appSecret"]:
        appSecret = os.environ.get("appSecret", dict["appSecret"])
    # responce_content=chat(dict["messages"]) #MsgFail '大瓦特服务调用时发生错误，请重试。'
    # responce_content=chat_stream(dict["messages"]) #MsgFail '大瓦特服务调用时发生错误，请重试。'

    # 手动迭代生成器
    answer = ''
    responce_content_stream = chat_stream(dict['messages'])
    try:
        while True:
            responce_content = next(responce_content_stream)  # 获取下一个yield产生的值
            answer += responce_content
            yield responce_content
    except StopIteration:
        pass
        # 生成器没有更多的值可以产生时，会抛出StopIteration异常
        # return ''

    if not answer:
        responce_content = "模型没有响应,请多试几次"
        yield responce_content


### -------------------------------- 知识库检索接口 --------------------------------
url_knowledge_vetor_query = f"{base_url}/knowledgeService/extChatApi/queryVector"

def knowledge_vetor_query(app_info, knowledgeIds,keywords='',topk=10):

    global appId, appSecret

    appId = app_info['appId']
    appSecret = app_info['appSecret']

    #请求参数
    request_params = {
        "knowledgeIds": knowledgeIds,
        "keywords":keywords,
        "topk": topk,
    }

    #更新appKey
    update_appkey(True)

    # 发送请求并读取响应
    response, resultMsg = post_json_2_dawate(url_knowledge_vetor_query, request_params)

    #如果错误，再尝试一次
    errmsg = check_error_response(response)
    # if errmsg is not None:
    #     # return errmsg
    #     # 发送请求并读取响应
    #     response = post_json_2_dawate(url_knowledge_vetor_query, request_params)
    #     errmsg = check_error_response(response)
    
    if errmsg is not None:
        return errmsg

    #show_json_response(response)
    
    return json.loads(response.content)['resultObject']

# if __name__ == "__main__":
#
#     ls = []
#     ls.append({"role": "user", "content": '肖建毅参与的项目有哪些'})
#     ls.append({"role": "assistant", "content": '''1、2018年，负责组织建设广东电网有限责任公司应用级灾备中心一期建设项目、广东电网公司营销系统维护、广东电网公司资产系统维护、广东电网公司财务系统维护、广东电网公司人资系统维护、广东电网公司GIS维护等项目。
# 2、2019年，负责组织建设广东电网有限责任公司应用级灾备中心二期建设项目、信息中心众测平台移动应用项目广东电网公司财务系统维护、广东电网公司信息中心1000号服务、广东电网公司营销系统维护、广东电网公司资产系统维护、广东电网公司财务系统维护、广东电网公司人资系统维护等项目。
# 3、2020年，负责组织建设IOS系统实用化项目及面向电力行业的数据库智能运维模型及应用研究项目、广东电网公司信息中心1000号服务、广东电网公司营销系统维护、广东电网公司资产系统维护、广东电网公司财务系统维护、广东电网公司人资系统维护等项目。
# 4、2021年，负责组织建设南方电网公司协同办公系统V2.0。'''})
#     # for i in range(5):
#     #     ls.append({"role": "user", "content": ''.join(["你是谁"]*5000)})
#     #     ls.append({"role": "assistant", "content": '我是大瓦特'})
#
#     for i in ls:
#         print(i)
#
    # config_params = {
    #     'relAppId': '17987690',
    #     'appId': '17987868',
    #     'appSecret': '5570ea83260dbcad482a7c9175411d5e',
    #     # 'messages': [{"role": "user", "content": ''.join(["你是谁"]*5000)}]
    #     'messages': [{"role": "user", "content": "你是谁"}]
    #     # 'messages': ls
    # }
    # a = ''
    # answer =''
    # response_content = main_stream(config_params)
    # print(response_content)
    # try:
    #     while True:
    #         a = next(response_content)
    #         print(a, end='')
    #         answer += a
    # except StopIteration:
    #     pass
    # answer = answer.split('</think>')[-1]
    # print(answer)
